#include "fadestackwidget.h"

#include <QVariantAnimation>
#include <QPainter>
#include <QEventLoop>

#include <stdexcept>
#include <format>


FadeStackWidget::FadeStackWidget(QWidget *parent) : QStackedWidget(parent) {
    //设置默认的时间间隔
    default_duration = 1000;
    //初始化animation框架、并连接信号和槽
    animation = new QVariantAnimation(this);
    connect(animation, &QVariantAnimation::valueChanged, this, &FadeStackWidget::onValueChange);
    connect(animation, &QVariantAnimation::finished, this, &FadeStackWidget::onAnimationFinished);
}

void FadeStackWidget::switchTo(int index) {
    if(index < 0 || index > count()){
        [[unlikely]]
        throw std::out_of_range(std::format("{}: Try to switch to index {}, but size is {}",__FUNCTION__ , index, count()));
    }
    switchTo(widget(index));
}


void FadeStackWidget::switchTo(QWidget *widget) {
    if(widget == nullptr){
        [[unlikely]]
        throw std::invalid_argument(std::format("{}: pass a nullptr", __FUNCTION__ ));
    }
    // 动画持续期间禁止切换
    if(animation->state() == QAbstractAnimation::Running){return;}

    currentWidget()->hide(); // 隐藏当前组件
    next_widget = widget;
    next_widget->resize(size());
    animation->setStartValue(0.0);
    animation->setEndValue(1.0);
    animation->setDuration(default_duration);
    animation->start();
}

void FadeStackWidget::paintEvent(QPaintEvent *event) {
    if(animation->state() == QAbstractAnimation::Running){
        QPainter painter(this);

        paintWidget(&painter, currentWidget(), 1 - currentValue.toReal());
        paintWidget(&painter, next_widget, currentValue.toReal());
    }
}
void FadeStackWidget::onValueChange(const QVariant &value) {
    currentValue = value;
    update();
}
void FadeStackWidget::onAnimationFinished() {
    currentWidget()->show();
    setCurrentWidget(next_widget);
    emit changeFinished();
}
void FadeStackWidget::paintWidget(QPainter *painter, QWidget *source, qreal opacity) {
    // HiDPI 支持
    qreal dpr = devicePixelRatioF();
    QPixmap widget_pix(source->width() * dpr, source->height() * dpr);
    widget_pix.setDevicePixelRatio(dpr);
    source->render(&widget_pix);
    painter->setOpacity(opacity);
    painter->drawPixmap(rect(), widget_pix);
}
